from rest_framework.response import Response
from rest_framework.decorators import action

from django.core.cache import cache

from usercenter.common.errors import get_error_info, WECHAT_AUTH_ERROR, WECHAT_AUTH_TIMEOUT_ERROR, WECHAT_AUTH_BIND_ERROR
from usercenter.common.redis_keys import WECHAT_OPEN_ID_KEY
from .base.wechat import wechatauth, create_user_from_wx
from .base.token import create_token
from .base.user import get_user_info, get_user_from_request, get_user_by_id, get_customer_user
from wechatpy.oauth import WeChatOAuthException
from rest_framework import viewsets
from usercenter.models import CustomerProfile

import logging
logger = logging.getLogger('userauth')


class WechatAuthViewSet(viewsets.GenericViewSet):
    """
    """
    queryset = CustomerProfile.objects.all()
    serializer_class = None
    permission_classes = ()

    @action(methods=['get'], detail=False)
    def qr(self, request, **kwargs):
        """
        获取微信登陆 QR地址
        """
        qrconnect_url = wechatauth.qrconnect_url
        qrconnect_url_info = {'qrconnect_url': qrconnect_url}
        return Response(qrconnect_url_info)

    @action(methods=['get'], detail=False)
    def auth(self, request, **kwargs):
        """
            微信登陆
            ```
            {'code': 0, 'message': '', 'user_info': None, 'token':''}
            http: 200
            1. 如果 token 为空, 则表明用户没有使用微信登陆过, 需要用户选择创建新账户或者绑定原有账户
            2. 如果 token 不为空, 登陆成功
            http: 400
            登陆异常
            ```
        """

        ret = {'code': 0, 'message': '', 'user_info': None, 'token': ''}
        code = request.GET.get('code', '')
        try:
            res = wechatauth.fetch_access_token(code)
        except WeChatOAuthException as e:
            logger.error(
                'access token error: code: %s, errmsg: %s' % (code, e.errmsg))
            ret.update(get_error_info(WECHAT_AUTH_ERROR))
            return Response(ret, 400)
        user = get_customer_user(res['openid'])
        if not user:
            cache.set(WECHAT_OPEN_ID_KEY % res['openid'], res, 10 * 3600)  # openid信息, 缓存10分钟
            try:
                user_info = wechatauth.get_user_info(openid=res['openid'], access_token=res['access_token'])
            except WeChatOAuthException as e:
                logger.error(
                    'get_user_info: openid: %s, errmsg: %s' % (res['openid'], e.errmsg))
                ret.update(get_error_info(WECHAT_AUTH_ERROR))
                return Response(ret, 400)

            ret['user_info'] = user_info
        else:
            ret['token'] = create_token(user)
            ret['user_info'] = get_user_info(user.id)

        return Response(ret)

    @action(methods=['get'], detail=False)
    def bind(self, request, format=None):

        """
            微信 创建或者绑定用户
            ```
            {'code': 0, 'message': '', 'user_info': None, 'token':''}
            http: 200
            1. 如果 token 为空, 则表明用户没有使用微信登陆过, 需要用户选择创建新账户或者绑定原有账户
            2. 如果 token 不为空, 登陆成功
            http: 400
            登陆异常
            ```

        """
        ret = {'code': 0, 'message': '', 'user_info': None, 'token': ''}

        openid = request.GET.get('openid', '')
        create = int(request.GET.get('create', 0))

        res = cache.get(WECHAT_OPEN_ID_KEY % openid, )
        if not res:
            ret.update(get_error_info(WECHAT_AUTH_TIMEOUT_ERROR))  # 微信登陆超时
            return Response(ret, 400)

        if create:  # 创建新用户
            try:
                user_info = wechatauth.get_user_info(openid=res['openid'], access_token=res['access_token'])
            except WeChatOAuthException as e:
                logger.error(
                    'get_user_info: openid: %s, errmsg: %s' % (openid, e.errmsg))
                ret.update(get_error_info(WECHAT_AUTH_ERROR))
                return Response(ret, 400)

            user = create_user_from_wx(user_info)
        else:  # 绑定原有用户
            try:
                user_info = get_user_from_request(request)  # 通过token获取用户
            except Exception as e:
                logger.info('获取原有用户失败.')
                ret.update(get_error_info(WECHAT_AUTH_BIND_ERROR))
                return Response(ret, 400)
            else:
                user = get_user_by_id(user_info['user_id'])

        ret['token'] = create_token(user)
        ret['user_info'] = get_user_info(user.id)

        return Response(ret)
